/*******************************************************************************
 * Copyright (c) 2005 Actuate Corporation.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License 2.0 which is available at
 * https://www.eclipse.org/legal/epl-2.0/.
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 *
 * Contributors:
 *  Actuate Corporation  - initial API and implementation
 *******************************************************************************/

package org.eclipse.birt.report.designer.data.ui.dataset;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.eclipse.birt.core.data.ExpressionUtil;
import org.eclipse.birt.core.data.IColumnBinding;
import org.eclipse.birt.core.exception.BirtException;
import org.eclipse.birt.data.engine.api.aggregation.AggregationManager;
import org.eclipse.birt.data.engine.api.aggregation.IAggrFunction;
import org.eclipse.birt.data.engine.api.aggregation.IParameterDefn;
import org.eclipse.birt.report.data.adapter.api.DataAdapterUtil;
import org.eclipse.birt.report.designer.data.ui.property.AbstractDescriptionPropertyPage;
import org.eclipse.birt.report.designer.data.ui.util.ControlProvider;
import org.eclipse.birt.report.designer.data.ui.util.DataSetExceptionHandler;
import org.eclipse.birt.report.designer.data.ui.util.DataSetExpressionProvider;
import org.eclipse.birt.report.designer.data.ui.util.DataSetProvider;
import org.eclipse.birt.report.designer.data.ui.util.DataUtil;
import org.eclipse.birt.report.designer.data.ui.util.IHelpConstants;
import org.eclipse.birt.report.designer.data.ui.util.Utility;
import org.eclipse.birt.report.designer.internal.ui.util.ExceptionHandler;
import org.eclipse.birt.report.designer.nls.Messages;
import org.eclipse.birt.report.designer.ui.ReportPlugin;
import org.eclipse.birt.report.designer.ui.dialogs.ExpressionBuilder;
import org.eclipse.birt.report.designer.util.DEUtil;
import org.eclipse.birt.report.model.api.AggregationArgumentHandle;
import org.eclipse.birt.report.model.api.ColumnHintHandle;
import org.eclipse.birt.report.model.api.ComputedColumnHandle;
import org.eclipse.birt.report.model.api.DataSetHandle;
import org.eclipse.birt.report.model.api.DesignElementHandle;
import org.eclipse.birt.report.model.api.PropertyHandle;
import org.eclipse.birt.report.model.api.StructureFactory;
import org.eclipse.birt.report.model.api.activity.SemanticException;
import org.eclipse.birt.report.model.api.elements.structures.AggregationArgument;
import org.eclipse.birt.report.model.api.elements.structures.ComputedColumn;
import org.eclipse.birt.report.model.api.metadata.IChoice;
import org.eclipse.birt.report.model.api.metadata.PropertyValueException;
import org.eclipse.birt.report.model.core.Structure;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.IMessageProvider;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;

/**
 * TODO: Please document
 *
 * @version $Revision$ $Date$
 */
public class DataSetComputedColumnsPage extends AbstractDescriptionPropertyPage {

	protected transient PropertyHandle computedColumns = null;
	protected transient PropertyHandleTableViewer viewer = null;

	private static final int COLUMN_NAME_INDEX = 0;
	private static final int DATA_TYPE_INDEX = 1;
	private static final int EXPRESSION_INDEX = 2;
	private static final int AGGREGATION_INDEX = 3;
//	private static final int ARGUMENT_INDEX = 4;
	private static final int FILTER_INDEX = 5;

	protected static String[] cellLabels = { Messages.getString("dataset.editor.title.columnName"), //$NON-NLS-1$
			Messages.getString("dataset.editor.title.dataType"), //$NON-NLS-1$
			Messages.getString("dataset.editor.title.expression"), //$NON-NLS-1$
			Messages.getString("dataset.editor.title.aggrFunc"), //$NON-NLS-1$
			Messages.getString("dataset.editor.title.aggrArgu"), //$NON-NLS-1$
			Messages.getString("dataset.editor.title.filter") //$NON-NLS-1$
	};

	protected static String[] cellProperties = { ComputedColumn.NAME_MEMBER, ComputedColumn.DATA_TYPE_MEMBER,
			ComputedColumn.EXPRESSION_MEMBER, ComputedColumn.AGGREGATEON_FUNCTION_MEMBER,
			ComputedColumn.ARGUMENTS_MEMBER, ComputedColumn.FILTER_MEMBER };

	protected static IChoice[] dataTypes = DEUtil.getMetaDataDictionary()
			.getStructure(ComputedColumn.COMPUTED_COLUMN_STRUCT).getMember(ComputedColumn.DATA_TYPE_MEMBER)
			.getAllowedChoices().getChoices();

	protected static String[] dialogLabels = { Messages.getString("dataset.editor.inputDialog.columnName"), //$NON-NLS-1$
			Messages.getString("dataset.editor.inputDialog.dataType"), //$NON-NLS-1$
			Messages.getString("dataset.editor.inputDialog.expression"), //$NON-NLS-1$
			Messages.getString("dataset.editor.inputDialog.aggrFunc"), //$NON-NLS-1$
			Messages.getString("dataset.editor.inputDialog.aggrArgu"), //$NON-NLS-1$
			Messages.getString("dataset.editor.inputDialog.filter") //$NON-NLS-1$
	};

	protected AggregationManager aggregationManager;

	/**
	 *
	 */
	public DataSetComputedColumnsPage() {
		super();
		try {
			aggregationManager = DataUtil.getAggregationManager().getInstance();
		} catch (BirtException e) {
			e.printStackTrace();
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#
	 * createPageControl(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	public Control createContents(Composite parent) {
		computedColumns = ((DataSetHandle) getContainer().getModel())
				.getPropertyHandle(DataSetHandle.COMPUTED_COLUMNS_PROP);

		createTableViewer(parent);
		addListeners();
		setToolTips();
		return viewer.getControl();
	}

	protected void createTableViewer(Composite parent) {
		viewer = new PropertyHandleTableViewer(parent, true, true, true) {

			@Override
			protected void doRemove() {
				int index = viewer.getTable().getSelectionIndex();
				PropertyHandle handle = (PropertyHandle) viewer.getInput();
				int count = (handle.getListValue() == null) ? 0 : handle.getListValue().size();

				if (index > -1 && index < count) {
					ComputedColumnHandle computedColumn = (ComputedColumnHandle) viewer.getTable().getItems()[index]
							.getData();
					removeColumnHint(computedColumn.getName());
					try {
						handle.removeItem(index);
					} catch (PropertyValueException e1) {
						ExceptionHandler.handle(e1);
					}

					viewer.refresh();
					viewer.getTable().setFocus();
					viewer.getTable().select(index);
					updateButtons();
				}
			}

			private void removeColumnHint(String columnName) {
				if (columnName == null) {
					return;
				}

				PropertyHandle propertyHandle = ((DataSetHandle) getContainer().getModel())
						.getPropertyHandle(DataSetHandle.COLUMN_HINTS_PROP);
				Iterator iter = propertyHandle.iterator();

				while (iter.hasNext()) {
					ColumnHintHandle hint = (ColumnHintHandle) iter.next();
					if (columnName.equals(hint.getColumnName())) {
						try {
							propertyHandle.removeItem(hint);
						} catch (PropertyValueException e) {
							ExceptionHandler.handle(e);
						}
					}
				}
			}

		};

		TableColumn column = new TableColumn(viewer.getViewer().getTable(), SWT.LEFT);
		column.setText(cellLabels[COLUMN_NAME_INDEX]);
		column.setWidth(150);
		column = new TableColumn(viewer.getViewer().getTable(), SWT.LEFT);
		column.setText(cellLabels[DATA_TYPE_INDEX]);
		column.setWidth(200);
		column = new TableColumn(viewer.getViewer().getTable(), SWT.LEFT);
		column.setText(cellLabels[EXPRESSION_INDEX]);
		column.setWidth(200);
		column = new TableColumn(viewer.getViewer().getTable(), SWT.LEFT);
		column.setText(cellLabels[AGGREGATION_INDEX]);
		column.setWidth(200);
		column = new TableColumn(viewer.getViewer().getTable(), SWT.LEFT);
		column.setText(cellLabels[FILTER_INDEX]);
		column.setWidth(200);
		viewer.getViewer().setContentProvider(new IStructuredContentProvider() {

			@Override
			public Object[] getElements(Object inputElement) {
				ArrayList computedColumnsList = new ArrayList(10);
				Iterator iter = computedColumns.iterator();
				if (iter != null) {
					while (iter.hasNext()) {
						computedColumnsList.add(iter.next());
					}
				}
				return computedColumnsList.toArray();
			}

			@Override
			public void dispose() {

			}

			@Override
			public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {

			}
		});
		viewer.getViewer().setLabelProvider(new TableProvider());
		viewer.getViewer().setInput(computedColumns);
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#
	 * pageActivated()
	 */
	@Override
	public void pageActivated() {
		try {
			refreshColumnNames();
			getContainer().setMessage(Messages.getString("dataset.editor.computedColumns"), //$NON-NLS-1$
					IMessageProvider.NONE); // $-NON-NLS-1
			// //$NON-NLS-1$
			setPageProperties();

			computedColumns = ((DataSetHandle) getContainer().getModel())
					.getPropertyHandle(DataSetHandle.COMPUTED_COLUMNS_PROP);

			viewer.getViewer().setInput(computedColumns);
			viewer.getViewer().getTable().select(0);
		} catch (BirtException e) {
			DataSetExceptionHandler.handle(e);
		}

	}

	/**
	 * Refresh columns meta data
	 *
	 * @throws BirtException
	 */
	private void refreshColumnNames() throws BirtException {
		((DataSetEditor) this.getContainer()).getCurrentItemModel(true);
	}

	private void addListeners() {
		viewer.getNewButton().addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				doNew();
			}
		});

		viewer.getEditButton().addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				doEdit();
			}
		});

		viewer.getViewer().getTable().addMouseListener(new MouseAdapter() {

			@Override
			public void mouseDoubleClick(MouseEvent e) {
				doEdit();
			}
		});

		viewer.getViewer().getTable().addKeyListener(new KeyListener() {

			@Override
			public void keyPressed(KeyEvent e) {
			}

			@Override
			public void keyReleased(KeyEvent e) {
				if (e.keyCode == SWT.DEL) {
					setPageProperties();
				}
			}

		});

		addRemoveListeners();

		viewer.getViewer().addSelectionChangedListener(new ViewerSelectionListener());
	}

	private void addRemoveListeners() {
		viewer.getRemoveButton().addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				setPageProperties();
				updateColumnsOfDataSetHandle();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}

		});

		viewer.getRemoveMenuItem().addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				setPageProperties();
				updateColumnsOfDataSetHandle();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}

		});

		viewer.getRemoveAllMenuItem().addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				setPageProperties();
				updateColumnsOfDataSetHandle();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
				widgetSelected(e);
			}
		});
	}

	private void doNew() {
		doEdit(new ComputedColumn(), true);
	}

	private void doEdit() {
		int index = viewer.getViewer().getTable().getSelectionIndex();
		if (index == -1) {
			return;
		}

		ComputedColumnHandle handle = (ComputedColumnHandle) viewer.getViewer().getTable().getItem(index).getData();

		doEdit(handle, false);
	}

	protected void doEdit(Object structureOrHandle, boolean applyAnalysis) {
		ComputedColumnInputDialog dlg = new ComputedColumnInputDialog(structureOrHandle, applyAnalysis);

		if (dlg.open() == Window.OK) {
			updateComputedColumn(structureOrHandle);
		}
	}

	protected void updateComputedColumn(Object structureOrHandle) {
		if (structureOrHandle instanceof ComputedColumn) {
			try {
				computedColumns.addItem((ComputedColumn) structureOrHandle);
				viewer.getViewer().refresh();
			} catch (SemanticException e) {
				ExceptionHandler.handle(e);
			}
		} else {
			viewer.getViewer().update(structureOrHandle, null);
		}

		if (validateAllComputedColumns()) {
			getContainer().setMessage(Messages.getString("dataset.editor.computedColumns"), //$NON-NLS-1$
					IMessageProvider.NONE);
		}

	}

	protected void updateColumnCache() {
		try {
			DataSetUIUtil.updateColumnCache((DataSetHandle) getContainer().getModel());
		} catch (SemanticException e) {
			ExceptionHandler.handle(e);
		}
	}

	protected ComputedColumn getStructure(Object structureOrHandle) {
		ComputedColumn structure = null;
		if (structureOrHandle instanceof ComputedColumn) {
			structure = (ComputedColumn) structureOrHandle;
		} else {
			structure = (ComputedColumn) ((ComputedColumnHandle) structureOrHandle).getStructure();
		}

		return structure;
	}

	protected final String getTypeName(String typeDisplayName) {
		for (int i = 0; i < dataTypes.length; i++) {
			if (dataTypes[i].getDisplayName().equals(typeDisplayName)) {
				return dataTypes[i].getName();
			}
		}

		return dataTypes[0].getName();
	}

	protected final String getTypeDisplayName(String typeName) {
		for (int i = 0; i < dataTypes.length; i++) {
			if (dataTypes[i].getName().equals(typeName)) {
				return dataTypes[i].getDisplayName();
			}
		}

		return typeName;
	}

	private void setToolTips() {
		viewer.getNewButton().setToolTipText(Messages.getString("DataSetComputedColumnsPage.toolTipText.New"));//$NON-NLS-1$
		viewer.getEditButton().setToolTipText(Messages.getString("DataSetComputedColumnsPage.toolTipText.Edit"));//$NON-NLS-1$
		viewer.getRemoveButton().setToolTipText(Messages.getString("DataSetComputedColumnsPage.toolTipText.Remove"));//$NON-NLS-1$
		viewer.getUpButton().setToolTipText(Messages.getString("DataSetComputedColumnsPage.toolTipText.Up"));//$NON-NLS-1$
		viewer.getDownButton().setToolTipText(Messages.getString("DataSetComputedColumnsPage.toolTipText.Down"));//$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.
	 * AbstractDescriptionPropertyPage#getPageDescription()
	 */
	@Override
	public String getPageDescription() {
		return Messages.getString("DataSetComputedColumnsPage.description"); //$NON-NLS-1$
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see
	 * org.eclipse.birt.report.designer.ui.dialogs.properties.AbstractPropertyPage#
	 * performOk()
	 */
	@Override
	public boolean performOk() {
		if (validateAllComputedColumns()) {
			return super.performOk();
		}
		return false;
	}

	private class TableProvider implements ITableLabelProvider {

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java
		 * .lang.Object, int)
		 */
		@Override
		public Image getColumnImage(Object element, int columnIndex) {
			return null;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.
		 * lang.Object, int)
		 */
		@Override
		public String getColumnText(Object element, int columnIndex) {
			String value = null;
			ComputedColumn computedColumn = getStructure(element);

			try {
				switch (columnIndex) {
				case 0: {
					value = computedColumn.getName();
					break;
				}
				case 1: {
					value = getTypeDisplayName(computedColumn.getDataType());
					break;
				}
				case 2: {
					// fetch the first argument as the expression value for
					// backward capability
					ComputedColumnHandle handle = (ComputedColumnHandle) computedColumn.getHandle(computedColumns);
					Iterator iterator = handle.argumentsIterator();
					if (iterator.hasNext()) {
						AggregationArgumentHandle argHandle = (AggregationArgumentHandle) iterator.next();
						value = argHandle.getValue();
					}
					if (value == null) {
						value = computedColumn.getExpression();
					}
					break;
				}
				case 3: {
					value = computedColumn.getAggregateFunction();
					IAggrFunction aggrFunc = aggregationManager.getAggregation(value);
					value = aggrFunc != null ? aggrFunc.getDisplayName() : value;
					break;
				}
				case 4: {
					value = computedColumn.getFilterExpression();
					break;
				}

				}
			} catch (Exception e) {
				ExceptionHandler.handle(e);
			}

			return (value == null ? "" : value); //$NON-NLS-1$
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#addListener(org.eclipse
		 * .jface.viewers.ILabelProviderListener)
		 */
		@Override
		public void addListener(ILabelProviderListener listener) {
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose()
		 */
		@Override
		public void dispose() {
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#isLabelProperty(java
		 * .lang.Object, java.lang.String)
		 */
		@Override
		public boolean isLabelProperty(Object element, String property) {
			return false;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.jface.viewers.IBaseLabelProvider#removeListener(org.eclipse
		 * .jface.viewers.ILabelProviderListener)
		 */
		@Override
		public void removeListener(ILabelProviderListener listener) {
		}

	}

	private class ViewerSelectionListener implements ISelectionChangedListener {

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.
		 * eclipse.jface.viewers.SelectionChangedEvent)
		 */
		@Override
		public void selectionChanged(SelectionChangedEvent event) {
			setPageProperties();
		}

	}

	/**
	 * Depending on the Computed the properties of various controls on this page are
	 * set
	 */
	private void setPageProperties() {
		viewer.updateButtons();
		validateAllComputedColumns();
	}

	/**
	 * Update the computed columns after removing an established one and cache the
	 * updated DataSetViewData[]
	 *
	 */
	private void updateColumnsOfDataSetHandle() {
		DataSetHandle dataSet = ((DataSetEditor) getContainer()).getHandle();
		DataSetViewData[] items;
		try {
			items = DataSetProvider.getCurrentInstance().getColumns(dataSet, false, true);
			int inexistence = 0;
			for (int i = 0; i < items.length; i++) {
				boolean exist = false;
				if (items[i].isComputedColumn()) {
					Iterator iter = computedColumns.iterator();
					while (iter.hasNext()) {
						ComputedColumn computedColumn = null;
						Object obj = iter.next();
						if (obj instanceof ComputedColumnHandle) {
							computedColumn = (ComputedColumn) ((ComputedColumnHandle) obj).getStructure();
						}
						if (computedColumn != null && items[i].getName().equals(computedColumn.getName())) {
							exist = true;
						}
					}
					if (!exist) {
						items[i] = null;
						inexistence++;
					}
				}
			}
			if (inexistence == 0) {
				return;
			}

			DataSetViewData[] existItems = new DataSetViewData[items.length - inexistence];
			int index = 0;
			for (int i = 0; i < items.length; i++) {
				if (items[i] != null) {
					existItems[index] = items[i];
					index++;
				}
			}
			DataSetProvider.getCurrentInstance().updateColumnsOfDataSetHandle(dataSet, existItems);
		} catch (BirtException e) {
			DataSetExceptionHandler.handle(e);
		}
	}

	/*
	 * (non-Javadoc)
	 *
	 * @see org.eclipse.birt.report.designer.ui.dialogs.properties.IPropertyPage#
	 * getToolTip()
	 */
	@Override
	public String getToolTip() {
		return Messages.getString("DataSetComputedColumnsPage.ComputedColumns.Tooltip"); //$NON-NLS-1$
	}

	@Override
	public boolean canLeave() {
		if (validateAllComputedColumns()) {
			updateColumnCache();
			return true;
		}
		return false;
	}

	/*
	 * Exam whether all registered computed columns are valid. Set the message of
	 * dialog as appropriated
	 */
	private boolean validateAllComputedColumns() {
		if (computedColumns != null) {
			Iterator iter = computedColumns.iterator();
			if (iter != null) {
				while (iter.hasNext()) {
					Object o = iter.next();
					ComputedColumn computedColumn = null;
					if (o instanceof ComputedColumnHandle) {
						computedColumn = (ComputedColumn) ((ComputedColumnHandle) o).getStructure();
					} else {
						computedColumn = (ComputedColumn) o;
					}
					if (!validateSingleColumn(computedColumn)) {
						return false;
					}
				}
			}
		}
		return true;
	}

	/*
	 * Exam whether one computed column is valid or not.
	 */
	private boolean validateSingleColumn(ComputedColumn computedColumn) {
		if (computedColumn.getName() == null || computedColumn.getName().trim().length() == 0) {
			getContainer().setMessage(Messages.getFormattedString("dataset.editor.error.missingComputedColumnName", //$NON-NLS-1$
					new Object[] { computedColumn.getName() }), IMessageProvider.ERROR);
			return false;
		}

		Iterator iter = ((DataSetHandle) getContainer().getModel()).getPropertyHandle(DataSetHandle.COLUMN_HINTS_PROP)
				.iterator();
		while (iter.hasNext()) {
			ColumnHintHandle hint = (ColumnHintHandle) iter.next();
			if (!computedColumn.getName().equals(hint.getColumnName())
					&& computedColumn.getName().equals(hint.getAlias())) {
				getContainer()
						.setMessage(Messages.getFormattedString("dataset.editor.error.computedColumnNameAlreadyUsed", //$NON-NLS-1$
								new Object[] { computedColumn.getName() }), IMessageProvider.ERROR);
				return false;
			}
		}
		return true;
	}

	/**
	 *
	 */
	protected static class DummyParamDefn implements IParameterDefn {
		String name;
		String displayName;
		String description = "";//$NON-NLS-1$
		boolean isDataField;
		boolean isOptional;

		/**
		 *
		 * @param name
		 * @param displayName
		 * @param isOptional
		 * @param isDataField
		 */
		public DummyParamDefn(String name, String displayName, boolean isOptional, boolean isDataField) {
			this.name = name;
			this.displayName = displayName;
			this.isDataField = isDataField;
			this.isOptional = isOptional;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.data.engine.api.aggregation.IParameterDefn#getDescription()
		 */
		@Override
		public String getDescription() {
			return description;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.data.engine.api.aggregation.IParameterDefn#getDisplayName()
		 */
		@Override
		public String getDisplayName() {
			return displayName;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.data.engine.api.aggregation.IParameterDefn#isDataField()
		 */
		@Override
		public boolean isDataField() {
			return isDataField;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.birt.data.engine.api.aggregation.IParameterDefn#isOptional()
		 */
		@Override
		public boolean isOptional() {
			return isOptional;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.data.engine.api.aggregation.IParameterDefn#supportDataType(
		 * int)
		 */
		@Override
		public boolean supportDataType(int dataType) {
			return true;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see org.eclipse.birt.data.engine.api.aggregation.IParameterDefn#getName()
		 */
		@Override
		public String getName() {
			return name;
		}
	}

	protected class ComputedColumnInputDialog extends PropertyHandleInputDialog {

		private static final String BLANK = "";//$NON-NLS-1$
		private Text txtColumnName = null;
		private Combo cmbDataType = null;
		private Combo cmbAggregation = null;

		private Label lblFilter = null;
		private Text txtFilter = null;
		private Button btnFilter = null;
		private String columnName = null;

		private Text[] txtParams = null; // parameter controls

		private IAggrFunction[] functions = null;
		private Composite parameterContainer;
		private Composite composite;
		private String lastExpression;
		private Label firstLabel;
		private int maxWidth;

		/**
		 *
		 * @param structureOrHandle
		 */
		private ComputedColumnInputDialog(Object structureOrHandle, boolean applyAnalysis) {
			super(structureOrHandle);
			populateFunctions();
		}

		@Override
		public void create() {
			super.create();
			validateSyntax();
		}

		@Override
		protected void setSystemHelp(Composite composite) {
			Utility.setSystemHelp(composite, IHelpConstants.CONEXT_ID_DATASET_COMPUTEDCOLUMNS_DIALOG);
		}

		/**
		 *
		 */
		private void populateFunctions() {
			List aggrList = aggregationManager.getAggregations(AggregationManager.AGGR_TABULAR);
			functions = new IAggrFunction[aggrList.size()];
			aggrList.toArray(functions);
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#
		 * createCustomControls(org.eclipse.swt.widgets.Composite)
		 */
		@Override
		protected void createCustomControls(Composite parent) {
			this.composite = parent;

			createTextCell(parent, COLUMN_NAME_INDEX);
			createComboBoxCell(parent, DATA_TYPE_INDEX);
			createAggrListCell(parent, AGGREGATION_INDEX);
			createParameterContainer(parent);
			createFilterCell(parent, FILTER_INDEX);
			handleAggrSelectEvent(getStructureOrHandle() instanceof Structure);
			createSpaceForResize(parent);
		}

		/**
		 * @param parent
		 */
		private void createSpaceForResize(Composite parent) {
			Label space = ControlProvider.createLabel(parent, null);
			space.setLayoutData(ControlProvider.getGridDataWithHSpan(3));
			space = ControlProvider.createLabel(parent, null);
			space.setLayoutData(ControlProvider.getGridDataWithHSpan(3));
			space = ControlProvider.createLabel(parent, null);
			space.setLayoutData(ControlProvider.getGridDataWithHSpan(3));
			space = ControlProvider.createLabel(parent, null);
			space.setLayoutData(ControlProvider.getGridDataWithHSpan(3));
		}

		/**
		 *
		 * @param parent
		 */
		private void createParameterContainer(Composite parent) {
			parameterContainer = new Composite(parent, SWT.NONE);
			GridData gridData = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
			gridData.horizontalIndent = 0;
			gridData.horizontalSpan = 3;
			gridData.exclude = true;
			parameterContainer.setLayoutData(gridData);
			GridLayout layout = new GridLayout();
			// layout.horizontalSpacing = layout.verticalSpacing = 0;
			layout.marginWidth = layout.marginHeight = 0;
			layout.numColumns = 3;
			parameterContainer.setLayout(layout);
		}

		/**
		 *
		 * @param parent
		 * @param index
		 */
		private void createTextCell(Composite parent, final int index) {
			firstLabel = ControlProvider.createLabel(parent, dialogLabels[index]);
			this.maxWidth = computeMaxWidth(firstLabel);

			txtColumnName = ControlProvider.createText(parent,
					(String) getProperty(getStructureOrHandle(), cellProperties[index]));
			txtColumnName.setLayoutData(ControlProvider.getGridDataWithHSpan(2));
			columnName = txtColumnName.getText();
			txtColumnName.addModifyListener(new ModifyListener() {

				@Override
				public void modifyText(ModifyEvent e) {
					validateSyntax();
				}
			});
		}

		/**
		 *
		 * @param parent
		 * @param index
		 */
		private void createComboBoxCell(Composite parent, final int index) {
			Label label = ControlProvider.createLabel(parent, dialogLabels[index]);
			this.maxWidth = computeMaxWidth(label);

			cmbDataType = ControlProvider.createCombo(parent, SWT.READ_ONLY);
			cmbDataType.setLayoutData(ControlProvider.getGridDataWithHSpan(2));
			cmbDataType.setVisibleItemCount(30);
			populateDataTypeComboItems();
			cmbDataType.select(Utility.findIndex(cmbDataType.getItems(),
					getTypeDisplayName((String) getProperty(getStructureOrHandle(), cellProperties[index]))));
			cmbDataType.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					validateSyntax();
				}

			});
		}

		/**
		 *
		 */
		private void populateDataTypeComboItems() {
			Map<String, String> indexMap = new HashMap<>();
			String[] dataTypeDisplayNames = new String[dataTypes.length];
			for (int i = 0; i < dataTypes.length; i++) {
				dataTypeDisplayNames[i] = dataTypes[i].getDisplayName();
				indexMap.put(dataTypeDisplayNames[i], dataTypes[i].getName());
			}
			Arrays.sort(dataTypeDisplayNames);
			cmbDataType.setItems(dataTypeDisplayNames);
			for (int i = 0; i < dataTypeDisplayNames.length; i++) {
				String name = (String) indexMap.get(dataTypeDisplayNames[i]);
				cmbDataType.setData(name, Integer.valueOf(i));
			}
		}

		/**
		 *
		 * @param parent
		 * @param index
		 */
		private void createAggrListCell(final Composite parent, final int index) {
			Label label = ControlProvider.createLabel(parent, dialogLabels[index]);
			this.maxWidth = computeMaxWidth(label);

			cmbAggregation = ControlProvider.createCombo(parent, SWT.READ_ONLY);
			cmbAggregation.setLayoutData(ControlProvider.getGridDataWithHSpan(2));
			cmbAggregation.setVisibleItemCount(30);
			cmbAggregation.add(BLANK);
			cmbAggregation.setData(BLANK, Integer.valueOf(0));
			for (int i = 0; i < functions.length; i++) {
				cmbAggregation.add(functions[i].getDisplayName());
				cmbAggregation.setData(functions[i].getName(), Integer.valueOf(i + 1));
			}

			String aggrFuncName = (String) getProperty(getStructureOrHandle(), cellProperties[index]);
			int selectionIndex = getAggrFuncIndex(aggrFuncName);
			cmbAggregation.select(selectionIndex);

			cmbAggregation.setToolTipText(selectionIndex > 0 ? functions[selectionIndex - 1].getDescription() : BLANK);

			cmbAggregation.addSelectionListener(new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent e) {
					handleAggrSelectEvent(true);
					validateSyntax();
					updateFilterUIStatus();
				}
			});

		}

		private int computeMaxWidth(Label label) {
			int widthHint = label.computeSize(-1, -1).x - label.getBorderWidth();
			return widthHint > this.maxWidth ? widthHint : this.maxWidth;
		}

		/**
		 *
		 */
		private void handleAggrSelectEvent(boolean resetDataType) {
			disposeOldParameterUI();
			IAggrFunction function = getSelectedFunction();
			IParameterDefn[] params = null;
			if (function != null) {
				params = function.getParameterDefn();
			} else {
				params = new IParameterDefn[] {
						new DummyParamDefn(cellLabels[EXPRESSION_INDEX], dialogLabels[EXPRESSION_INDEX], false, true) };
			}
			if (params.length > 0) {
				showParameterUISection();
				createParameterUISection(params);
			} else {
				hideParameterUISection();
			}

			if (resetDataType) {
				updateDataTypeCombo();
			}
			parameterContainer.layout();
			composite.layout();
		}

		/**
		 * @param params
		 */
		private void createParameterUISection(IParameterDefn[] params) {
			txtParams = new Text[params.length];
			for (int i = 0; i < params.length; i++) {
				IParameterDefn param = params[i];
				Label paramLabel = new Label(parameterContainer, SWT.NONE | SWT.WRAP);
				paramLabel.setText(Utility.getNonNullString(param.getDisplayName()));

				GridData gd = new GridData();
				this.maxWidth = computeMaxWidth(paramLabel);
				gd.widthHint = this.maxWidth;
				paramLabel.setLayoutData(gd);
				Composite composite = ControlProvider.getDefaultComposite(parameterContainer);
				if (param.isDataField()) {
					String text = BLANK;
					if (lastExpression != null) {
						text = lastExpression;
					} else {
						text = (String) getProperty(getStructureOrHandle(), cellProperties[EXPRESSION_INDEX]);
					}
					txtParams[i] = ControlProvider.createText(composite, text);
					final Text txtDataField = txtParams[i];

					txtDataField.setLayoutData(ControlProvider.getGridDataWithHSpan(1));
					txtDataField.setData(params[i]);

					txtDataField.addModifyListener(new ModifyListener() {

						@Override
						public void modifyText(ModifyEvent e) {
							lastExpression = txtDataField.getText();
							validateSyntax();
						}

					});
				} else {
					Text txtArgument = ControlProvider.createText(composite, null);
					txtArgument.setLayoutData(ControlProvider.getGridDataWithHSpan(1));
					txtArgument.addModifyListener(new ModifyListener() {

						@Override
						public void modifyText(ModifyEvent e) {
							validateSyntax();
						}

					});
					txtParams[i] = txtArgument;
				}
				txtParams[i].setToolTipText(param.getDescription());
				createExpressionButton(composite, txtParams[i]);
			}

			updateLabelWidth();
			// update parameters' values from ComputedColumnHandle
			updateParametersText(params);
		}

		private void updateLabelWidth() {
			GridData gd = new GridData();
			gd.widthHint = this.maxWidth;
			firstLabel.setLayoutData(gd);
		}

		/**
		 *
		 */
		private void updateDataTypeCombo() {
			final IAggrFunction aggrFunc = getSelectedFunction();
			if (aggrFunc != null) {
				String dataType = DataAdapterUtil.adapterToModelDataType(aggrFunc.getDataType());
				cmbDataType.setText(getTypeDisplayName(dataType));
			}
		}

		/**
		 *
		 */
		private void disposeOldParameterUI() {
			Control[] children = parameterContainer.getChildren();
			for (int i = 0; i < children.length; i++) {
				children[i].dispose();
			}
		}

		/**
		 *
		 */
		private void hideParameterUISection() {
			((GridData) parameterContainer.getLayoutData()).heightHint = 0;
		}

		/**
		 *
		 */
		private void showParameterUISection() {
			((GridData) parameterContainer.getLayoutData()).exclude = false;
			((GridData) parameterContainer.getLayoutData()).heightHint = SWT.DEFAULT;
		}

		/**
		 * update the arguments' UI elements from the compute column handle.
		 */
		private void updateParametersText(IParameterDefn[] params) {
			if (params.length == 0) {
				return;
			}
			Object handle = getStructureOrHandle();
			if (handle instanceof ComputedColumnHandle) {
				ComputedColumnHandle cHandle = (ComputedColumnHandle) handle;
				String expr = cHandle.getExpression();
				if (expr != null) {
					txtParams[0].setText(expr);
				} else {
					Iterator itr = cHandle.argumentsIterator();
					List argHandles = new ArrayList();
					while (itr.hasNext()) {
						argHandles.add(itr.next());
					}
					int i = 0;
					if (params[0].isDataField() && lastExpression != null) {
						txtParams[0].setText(lastExpression);
						i++;
					}
					for (; i < params.length; i++) {
						AggregationArgumentHandle argHandle = null;
						if (i < argHandles.size()) {
							argHandle = (AggregationArgumentHandle) argHandles.get(i);
						}
						final String value = argHandle != null ? argHandle.getValue() : null;
						txtParams[i].setText(value != null ? value : BLANK);
					}
				}
			}
		}

		/**
		 *
		 * @param aggrFuncName
		 * @return
		 */
		private int getAggrFuncIndex(String aggrFuncName) {
			Integer selectionIndex = (Integer) cmbAggregation.getData(aggrFuncName != null ? aggrFuncName : BLANK);
			return selectionIndex != null ? selectionIndex.intValue() : 0;
		}

		/**
		 * @return whether filter component should be enabled
		 */
		private boolean needFilter() {
			if (cmbAggregation.getText() != null && cmbAggregation.getText().trim().length() > 0) {
				return true;
			} else {
				return false;
			}
		}

		/**
		 * Update the Filter component status
		 */
		private void updateFilterUIStatus() {
			if (needFilter()) {
				txtFilter.setEnabled(true);
				lblFilter.setEnabled(true);
				btnFilter.setEnabled(true);
			} else {
				txtFilter.setText(BLANK);
				txtFilter.setEnabled(false);
				lblFilter.setEnabled(false);
				btnFilter.setEnabled(false);
			}
		}

		/**
		 *
		 * @param parent
		 * @param index
		 */
		private void createFilterCell(Composite parent, final int index) {
			lblFilter = ControlProvider.createLabel(parent, dialogLabels[index]);

			Composite composite = ControlProvider.getDefaultComposite(parent);
			Object handle = this.getStructureOrHandle();
			if (handle instanceof ComputedColumnHandle) {
				ComputedColumnHandle cHandle = (ComputedColumnHandle) handle;
				txtFilter = ControlProvider.createText(composite, cHandle.getFilterExpression());

			} else {
				txtFilter = ControlProvider.createText(composite,
						(String) getProperty(getStructureOrHandle(), cellProperties[index]));
			}
			txtFilter.setLayoutData(ControlProvider.getGridDataWithHSpan(1));
			txtFilter.setEnabled(false);
			txtFilter.addModifyListener(new ModifyListener() {

				@Override
				public void modifyText(ModifyEvent e) {
					validateSyntax();
				}

			});

			SelectionAdapter listener = new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent event) {
					ExpressionBuilder expressionBuilder = new ExpressionBuilder(txtFilter.getText());
					expressionBuilder.setExpressionProvier(
							new DataSetExpressionProvider((DesignElementHandle) getContainer().getModel()));
					String expression = txtFilter == null ? null : txtFilter.getText();
					setExprBuilderDefaultSelection(expressionBuilder, expression);

					if (expressionBuilder.open() == OK) {
						txtFilter.setText(expressionBuilder.getResult().trim());
					}
				}
			};

			btnFilter = ControlProvider.createButton(composite, SWT.PUSH, listener);
			updateFilterUIStatus();
		}

		/**
		 *
		 * @param composite
		 * @param text
		 * @return
		 */
		private Button createExpressionButton(Composite composite, final Text text) {
			SelectionAdapter listener = new SelectionAdapter() {

				@Override
				public void widgetSelected(SelectionEvent event) {
					ExpressionBuilder expressionBuilder = new ExpressionBuilder(text.getText());
					expressionBuilder.setExpressionProvier(
							new DataSetExpressionProvider((DesignElementHandle) getContainer().getModel()));
					String expression = (txtParams.length > 0 && txtParams[0] != null) ? txtParams[0].getText() : null;
					setExprBuilderDefaultSelection(expressionBuilder, expression);

					if (expressionBuilder.open() == OK) {
						text.setText(expressionBuilder.getResult().trim());
					}
				}
			};

			return ControlProvider.createButton(composite, SWT.PUSH, listener);
		}

		/**
		 * Set the default selection in the expression builder
		 *
		 * @param expressionBuilder
		 */
		private void setExprBuilderDefaultSelection(ExpressionBuilder expressionBuilder, String expression) {
			Object[] selection = null;
			String dataSets = DataSetExpressionProvider.DATASETS;
			DataSetHandle dsHandle = (DataSetHandle) getContainer().getModel();
			Object handle = this.getStructureOrHandle();
			if (handle instanceof ComputedColumnHandle) {
				try {
					String columnName = ExpressionUtil.getColumnBindingName(expression);
					DataSetViewData viewData = findDataSetViewData(columnName, dsHandle);
					selection = new Object[] { dataSets, dsHandle, viewData };
				} catch (BirtException e) {
					selection = new Object[] { dataSets, dsHandle };
				}
			} else {
				selection = new Object[] { dataSets, dsHandle };
			}
			expressionBuilder.setDefaultSelection(selection);
		}

		/**
		 * Finds the DataSetViewData instance according to the given column name
		 *
		 * @param columnName
		 * @param handle
		 * @return
		 */
		private DataSetViewData findDataSetViewData(String columnName, DataSetHandle handle) {
			if (columnName == null || columnName.trim().length() == 0) {
				return null;
			}
			try {
				DataSetViewData[] items = DataSetProvider.getCurrentInstance().getColumns(handle, false, true);
				for (int i = 0; i < items.length; i++) {
					if (columnName.equals(items[i].getName())) {
						return items[i];
					}
				}
			} catch (BirtException e) {
				DataSetExceptionHandler.handle(e);
			}
			return null;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#
		 * validateSemantics(java.lang.Object)
		 */
		@Override
		protected IStatus validateSemantics(Object structureOrHandle) {
			AggregationArgument aggrArgument = null;
			String columnName = txtColumnName.getText();
			String dataTypeName = getTypeName(cmbDataType.getText());
			IAggrFunction aggrFunc = getSelectedFunction();

			try {
				String funcName = aggrFunc != null ? aggrFunc.getName() : BLANK;
				String filter = this.txtFilter.getText();
				if (structureOrHandle instanceof ComputedColumnHandle) {
					ComputedColumnHandle handle = (ComputedColumnHandle) structureOrHandle;
					handle.setName(columnName);
					handle.setDataType(dataTypeName);
					handle.setAggregateFunction(funcName);
					if (aggrFunc == null) {
						handle.setExpression(txtParams[0].getText().trim());
					} else {
						handle.setExpression(BLANK);
						handle.setFilterExpression(filter);
						handle.clearArgumentList();
						IParameterDefn[] params = aggrFunc.getParameterDefn();
						for (int i = 0; i < params.length; i++) {
							if (txtParams[i].getText().trim().length() == 0) {
								continue;
							}
							aggrArgument = StructureFactory.createAggregationArgument();
							aggrArgument.setName(params[i].getName());
							aggrArgument.setValue(txtParams[i].getText().trim());
							handle.addArgument(aggrArgument);
						}
					}
				} else if (structureOrHandle instanceof ComputedColumn) {
					ComputedColumn handle = (ComputedColumn) structureOrHandle;
					handle.setName(columnName);
					handle.setDataType(dataTypeName);
					handle.setAggregateFunction(funcName);
					if (aggrFunc == null) {
						handle.setExpression(txtParams[0].getText().trim());
					} else {
						handle.setExpression(BLANK);
						handle.setFilterExpression(filter);
						IParameterDefn[] params = aggrFunc.getParameterDefn();
						for (int i = 0; i < params.length; i++) {
							if (txtParams[i].getText().trim().length() == 0) {
								continue;
							}
							aggrArgument = StructureFactory.createAggregationArgument();
							aggrArgument.setName(params[i].getName());
							aggrArgument.setValue(txtParams[i].getText().trim());
							handle.addArgument(aggrArgument);
						}
					}
					updateComputedColumns(handle);
				}
			} catch (Exception e) {
				Status status = new Status(IStatus.ERROR, ReportPlugin.REPORT_UI, BLANK, e);
				return status;
			}
			return getOKStatus();
		}

		/**
		 *
		 * @return
		 */
		private IAggrFunction getSelectedFunction() {
			int index = cmbAggregation.getSelectionIndex();
			return index > 0 ? functions[index - 1] : null;
		}

		/**
		 * Update the computed columns after adding a new column and cache the updated
		 * DataSetViewData[]
		 *
		 */
		private void updateComputedColumns(ComputedColumn handle) {
			try {
				DataSetHandle dataSet = ((DataSetEditor) getContainer()).getHandle();
				DataSetViewData[] items = DataSetProvider.getCurrentInstance().getColumns(dataSet, false, true);
				int count = items.length;
				DataSetViewData[] newItems = new DataSetViewData[count + 1];
				System.arraycopy(items, 0, newItems, 0, count);
				newItems[count] = new DataSetViewData();
				newItems[count].setName(handle.getName());
				newItems[count].setDataTypeName(handle.getDataType());
				newItems[count].setAlias(handle.getDisplayName());
				newItems[count].setComputedColumn(true);
				newItems[count].setPosition(count + 1);
				newItems[count].setDataType(DataAdapterUtil.adaptModelDataType(handle.getDataType()));

				DataSetProvider.getCurrentInstance().updateColumnsOfDataSetHandle(dataSet, newItems);
			} catch (BirtException e) {
				DataSetExceptionHandler.handle(e);
			}
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#
		 * validateSyntax(java.lang.Object)
		 */
		@Override
		protected IStatus validateSyntax(Object structureOrHandle) {
			try {
				// duplicated columnName check
				if (!isUniqueColumnName()) {
					return getMiscStatus(IStatus.ERROR,
							Messages.getString("DataSetComputedColumnsPage.duplicatedName")); //$NON-NLS-1$
				}

				// blankProperty check
				if (isBlankProperty(txtColumnName.getText())) {
					return getBlankPropertyStatus(dialogLabels[COLUMN_NAME_INDEX]);
				}
				if (isBlankProperty(cmbDataType.getText())) {
					return getBlankPropertyStatus(dialogLabels[DATA_TYPE_INDEX]);
				}
				// ColumnName is number
				if (isNumeric(txtColumnName.getText())) {
					return getMiscStatus(IStatus.ERROR, Messages.getString("DataSetComputedColumnsPage.numberName"));
				}
//				if ( expression!=null && isBlankProperty( expression.getText( ) ) )
//				{
//					String funcName = getSelectedFunction( ).getName( );
//					if ( isFunctionCount( funcName ) == false )
//						return getBlankPropertyStatus( cellLabels[EXPRESSION_INDEX] );
//				}
				// validate arguments
				IAggrFunction aggrFunc = getSelectedFunction();
				if (aggrFunc != null) {
					IParameterDefn[] paramDefns = aggrFunc.getParameterDefn();
					for (int i = 0; i < paramDefns.length; i++) {
						if (!paramDefns[i].isOptional() && isBlankProperty(txtParams[i].getText())) {
							return getBlankPropertyStatus(paramDefns[i].getDisplayName());
						}
					}
				} else if (txtParams != null && isBlankProperty(txtParams[0].getText())) {
					return getBlankPropertyStatus(dialogLabels[EXPRESSION_INDEX]);
				}

				if (cmbAggregation != null && cmbAggregation.getText().trim().length() > 0
						&& !checkExpressionBindingFields()) {
					return getMiscStatus(IStatus.ERROR, Messages
							.getString("DataSetComputedColumnsPage.InputDialog.message.error.AggregationExpression")); //$NON-NLS-1$
				}
			} catch (BirtException e) {
				e.printStackTrace();
			}
			return getOKStatus();
		}

		/**
		 * If text is a decimal presentation of int32 value, then text is index. In this
		 * case return true and make send out error message. Otherwise return false
		 * means the column name is right.
		 */
		private boolean isNumeric(String text) {
			long indexTest = indexFromString(text);
			if (indexTest >= 0) {
				return true;
			}
			return false;
		}

		private long indexFromString(String str) {
			// The length of the decimal string representation of
			// Integer.MAX_VALUE, 2147483647
			final int MAX_VALUE_LENGTH = 10;

			int len = str.length();
			if (len > 0) {
				int i = 0;
				boolean negate = false;
				int c = str.charAt(0);
				if (c == '-') {
					if (len > 1) {
						c = str.charAt(1);
						i = 1;
						negate = true;
					}
				}
				c -= '0';
				if (0 <= c && c <= 9 && len <= (negate ? MAX_VALUE_LENGTH + 1 : MAX_VALUE_LENGTH)) {
					// Use negative numbers to accumulate index to handle
					// Integer.MIN_VALUE that is greater by 1 in absolute value
					// then Integer.MAX_VALUE
					int index = -c;
					int oldIndex = 0;
					i++;
					if (index != 0) {
						// Note that 00, 01, 000 etc. are not indexes
						while (i != len && 0 <= (c = str.charAt(i) - '0') && c <= 9) {
							oldIndex = index;
							index = 10 * index - c;
							i++;
						}
					}
					// Make sure all characters were consumed and that it
					// couldn't
					// have overflowed.
					if (i == len && (oldIndex > (Integer.MIN_VALUE / 10) || (oldIndex == (Integer.MIN_VALUE / 10)
							&& c <= (negate ? -(Integer.MIN_VALUE % 10) : (Integer.MAX_VALUE % 10))))) {
						return 0xFFFFFFFFL & (negate ? index : -index);
					}
				}
			}
			return -1L;
		}

		private boolean checkExpressionBindingFields() throws BirtException {
			for (int i = 0; i < txtParams.length; i++) {
				if (txtParams[i].getData() instanceof IParameterDefn) {
					IParameterDefn paramDefn = (IParameterDefn) txtParams[i].getData();
					if (paramDefn.isDataField()) {
						String expr = txtParams[i].getText();
						List columns = ExpressionUtil.extractColumnExpressions(expr, ExpressionUtil.ROW_INDICATOR);
						columns.addAll(
								ExpressionUtil.extractColumnExpressions(expr, ExpressionUtil.DATASET_ROW_INDICATOR));
						for (int k = 0; k < columns.size(); k++) {
							String columnName = ((IColumnBinding) columns.get(k)).getResultSetColumnName();
							ComputedColumnHandle item = findComputedColumn(columnName);
							if (item != null && item.getAggregateFunction() != null) {
								return false;
							}
						}
					}
				}
			}
			return true;
		}

		private ComputedColumnHandle findComputedColumn(String name) {
			if (name == null || name.trim().length() == 0) {
				return null;
			}

			PropertyHandle properyHandle = ((DataSetEditor) getContainer()).getHandle()
					.getPropertyHandle(DataSetHandle.COMPUTED_COLUMNS_PROP);
			if (properyHandle != null) {
				Iterator iter = properyHandle.iterator();
				while (iter.hasNext()) {
					ComputedColumnHandle computedColumn = (ComputedColumnHandle) iter.next();
					if (name.equals(computedColumn.getName())) {
						return computedColumn;
					}
				}
			}
			return null;
		}

		/**
		 *
		 * @return
		 * @throws BirtException
		 */
		private final boolean isUniqueColumnName() throws BirtException {
			DataSetViewData[] items = DataSetProvider.getCurrentInstance()
					.getColumns(((DataSetEditor) getContainer()).getHandle(), true);

			for (int i = 0; i < items.length; i++) {
				if (!items[i].getName().equals(columnName)) {
					if (!items[i].isComputedColumn()) {
						if ((items[i].getAlias() != null && items[i].getAlias().equals(txtColumnName.getText()))
								|| (items[i].getName() != null && items[i].getName().equals(txtColumnName.getText()))) {
							return false;
						}
					}
				}

			}
			Iterator iter = computedColumns.iterator();
			if (iter != null) {
				while (iter.hasNext()) {
					ComputedColumnHandle handle = (ComputedColumnHandle) iter.next();
					if (getStructure(getStructureOrHandle()) != handle.getStructure()
							&& handle.getName().equals(txtColumnName.getText())) {
						return false;
					}
				}
			}
			Iterator iter2 = ((DataSetHandle) getContainer().getModel())
					.getPropertyHandle(DataSetHandle.COLUMN_HINTS_PROP).iterator();
			while (iter2.hasNext()) {
				ColumnHintHandle hint = (ColumnHintHandle) iter2.next();
				if (!hint.getColumnName().equals(columnName)) {
					if (txtColumnName.getText().equals(hint.getAlias())
							|| txtColumnName.getText().equals(hint.getColumnName())) {
						return false;
					}
				}

			}

			return true;
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#
		 * rollback()
		 */
		@Override
		protected void rollback() {
		}

		/*
		 * (non-Javadoc)
		 *
		 * @see
		 * org.eclipse.birt.report.designer.data.ui.dataset.PropertyHandleInputDialog#
		 * getTitle()
		 */
		@Override
		protected String getTitle() {
			if (this.getStructureOrHandle() instanceof Structure) {
				return Messages.getString("DataSetComputedColumnsPage.InputDialog.title.New"); //$NON-NLS-1$
			}
			return Messages.getString("DataSetComputedColumnsPage.InputDialog.title.Edit");//$NON-NLS-1$
		}

	}

}
